#ifndef INDEXEDMESH
#define INDEXEDMESH
#include "GE_Base.h"
namespace Syp
{
///A VertexWeightSet describes all the skinning information for 1 vertex
struct VertexWeightSet
{
	PShortArray BoneID;///X number of bones
	FloatArray weight;///X number of weights where X is equivalent in both cases
};
///A keyframe holds positional/orientation information for a particular time/frame.
struct KeyFrame
{
	Quat Rot;
	Point3 Pos;
	///time in seconds
	float time;
	bool operator<(const KeyFrame& right) const
	{
        return (this->time < right.time);
	};
	bool operator< (const float right) const
	{
        return (this->time < right);
	};

	bool operator> (const KeyFrame& right) const
	{
        return (this->time > right.time);
	};
	bool operator> (const float right) const
	{
        return (this->time > right);
	};
};

///A bone is well, a bone.
struct Bone : public Node
{
	Bone():currTime(0.0f)
	{		
		invCalculated = false;
	};
	///String name of bone, useful for debugging perhaps
	String name;
	///ID of Bone
	short ID;
	/////Orientation of bone
	//Quat rot;
	/////initial position of bone
	//Point3 pos;
	/////Parent ID of this bone, -1 if it doesnt have a parent
	//short Parent;
	///Pointer to parent bone
	//Bone* ParentPtr;
	///Key frames
	std::vector<KeyFrame> KFrame;  
	///Matrix which brings bone back to identity
	float inv[16];
	///Matrix which brings bone back to its old position (Translation only)
	float invB[16];
	///All the calculations after bone is at identity (HeadBanging solution)
	float forward[16];
	///Current transformation matrix
	float mat[16];
    ///For determining if inverse matrix has been calculated
	bool invCalculated;
	///currently transformed at this system time
	float currTime;
};

///Standard Mesh with indices for rendering
class SYPAPI IndexedMesh : public BaseMesh
{
	friend class Renderer;
public:	
	static IndexedMesh* createIndexedMesh(const String& filename,ModelType t);	
	static void destroyIndexedMesh(IndexedMesh* mesh);
	virtual void updateMesh();
	///Draws the mesh
	virtual void draw();
	virtual void removeFromVRAM();	
	///Returns if Mesh contains skinning information
	bool isSkinned();
	///Loads a mesh from a file,adds it and returns a pointer to the	mesh. The parameter addToEngine is true by default and defines whether the mesh should be added to the Renderer. Resources managed by the Engine are deleted automatically when they are no longer needed. autoUpdateMesh variable helps the user to update the mesh and send it to the gfx card.
	static IndexedMesh* loadFromFile(const String& fileName, bool autoUpdateMesh = true);
//	static IndexedMesh* loadFromFile2(const String& fileName, bool autoUpdateMesh = true);
	///Writes the mesh to a file. This file can be loaded by using loadFromFile(). Writes SYP File Format v0.1
	void writeToFile(const String& name);
	
  	///Transforms the bone to the current animation frame
	void transformBone(Bone& b);
	
	///Returns the current AnimationTime
	float getCurrAnimTrans();
	///Sets the currentAnimationTime
	void setCurrAnimTrans(float currTime);
	///Sets whether mesh is skinned, intended to be used by file exporters/converters
	void setHasSkin(bool gotSkin);
	///Sets the Bind pose matrix
	void setBindPoseMatrix(float* mat);
	///Gets the Bind Pose matrix
	float* getBindPoseMatrix();

	///Returns a reference to skin ID(Indices for each vertex referring to the VWeight they use, reason is because when exporting many similar vertices are split because of different normals/UV coord, so it is more efficient to only store skinning info for unique vertices by position.).
	PShortArray& getSkinIDRef();
	///Returns a reference to the VWeights vector. Vweights hold all required skinning information for a/group of vertices.
	std::vector<VertexWeightSet>& getVWeightsRef();
	///Returns a reference to the backup data
	FloatArray& getBakDataRef();
	///Returns a reference to the Indices array
	PShortArray& getIndexArrayRef();
	///Sets the skeleton to use to animate the mesh.Skeleton must be compatible with mesh to be used.
	void useSkeleton(Skeleton* sk);
	///Returns a pointer to the skeleton being used by mesh.
	Skeleton* getSkeleton();
	///IndexedMesh destructor, never delete an IndexedMesh, always use destroyIndexedMesh static function.
	virtual ~IndexedMesh();


private:
	///stores whether this mesh has a skin
	bool hasSkin;	
	IndexedMesh(const String& filename,ModelType t);	
	///ID's generated by GL
	PInt indexID;
	///Indices
	PShortArray index;
	

	///Skeletal Animation data	
	/////////////////////////////////////SKINNING INFO///////////////////////////////////////////////////////
	///Indices for each vertex referring to the VWeight they use, reason is because when exporting many similar vertices are split because of different normals/UV coord, so it is more efficient to only store skinning info for unique vertices by position.
	PShortArray skinID;

	///the VWeights which have all the skinning information
	std::vector<VertexWeightSet> VWeights;
	///Pointer to the skeleton to use
	Skeleton* skeleton;
	///The bindPose matrix
	float bindMat[16];


	///This is backup data of the original mesh in it's initial position/pose. If during mesh loading, the file has a skin, a backup copy is made and kept in bakdata. This copy is not made if the mesh does not have any skin animation.
	FloatArray bakData;		
	
	///Currently transformed at this time
	float currAnimTrans;

};
}
#endif

